package com.sunpy.permissionservice.login.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.api.R;
import com.sunpy.commonservice.exception.CommonException;
import com.sunpy.commonservice.model.ResultModel;
import com.sunpy.commonservice.util.JwtUtil;
import com.sunpy.commonservice.util.RedisCache;
import com.sunpy.commonservice.util.SnowFlakeIdUtil;
import com.sunpy.commonservice.util.TimeUtil;
import com.sunpy.permissionservice.bo.MachineBO;
import com.sunpy.permissionservice.bo.MenuBO;
import com.sunpy.permissionservice.bo.RoleBO;
import com.sunpy.permissionservice.dao.MenuMapper;
import com.sunpy.permissionservice.dao.RoleMapper;
import com.sunpy.permissionservice.login.model.LoginUserDetailBO;
import com.sunpy.permissionservice.bo.UserBO;
import com.sunpy.permissionservice.po.Menu;
import com.sunpy.permissionservice.po.Role;
import com.sunpy.permissionservice.po.User;
import com.sunpy.permissionservice.dao.UserMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author sunpy
 * @since 2022-09-260
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private MachineBO machine;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;

    @Value("${sys.login-jwt.expire}")
    private int expireJWT;

    @Value("${sys.login-redis.expire}")
    private int expireRedis;

    @Transactional
    @Override
    public ResultModel<String> insertUser(UserBO userBO) throws CommonException {
        ResultModel<String> resultModel = new ResultModel<>();
        User user = new User();
        BeanUtil.copyProperties(userBO, user);
        Long datacenterId = machine.getDatacenterId();
        Long workerId = machine.getWorkerId();
        SnowFlakeIdUtil snowFlakeIdUtil = new SnowFlakeIdUtil(workerId, datacenterId);
        Long id = snowFlakeIdUtil.genNextId();
        user.setUserId(id);

        String createBy = "machine-" +
                datacenterId +
                "-" +
                workerId;
        user.setCreateBy(createBy);
        user.setCreateTime(TimeUtil.getLocalDateTime());
        user.setUpdateTime(TimeUtil.getLocalDateTime());
        userMapper.insert(user);

        resultModel.setMsg("用户插入成功！");
        resultModel.setRes(String.valueOf(id));
        return resultModel;
    }

    @Override
    public ResultModel<String> login(UserBO userBO) throws CommonException {
        /**
         * 1. 获取授权信息
         */
        UsernamePasswordAuthenticationToken token =
                new UsernamePasswordAuthenticationToken(userBO.getUserName(), userBO.getPassword());
        Authentication authentication = authenticationManager.authenticate(token);

        if (Objects.isNull(authentication)) {
            throw new CommonException("登录失败");
        }

        /**
         * 获取授权信息中的用户信息
         */
        LoginUserDetailBO loginUserDetailBO = (LoginUserDetailBO) authentication.getPrincipal();
        String userIdStr = loginUserDetailBO.getUserBO().getUserId().toString();

        /**
         * 用户登录，认证成功，那么生成JWT，下次直接使用JWT访问
         */
        String jwt = JwtUtil.createJWT("userId" , userIdStr, expireJWT);

        /**
         * 将用户信息存储到redis
         */
        redisCache.setCacheObject("token:"+ userIdStr, loginUserDetailBO);
        redisCache.expire("token:"+ userIdStr, expireRedis);

        ResultModel<String> resultModel = new ResultModel<>();
        resultModel.setMsg("登录成功");
        resultModel.setRes(jwt);
        return resultModel;
    }

    @Override
    public ResultModel<LoginUserDetailBO> selectAllByUser(String username) throws CommonException {
        if (StrUtil.isBlank(username)) {
            throw new CommonException("用户" + username + "不存在");
        }

        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("user_name", username);
        User user = userMapper.selectOne(queryWrapper);

        if (Objects.isNull(user)) {
            throw new CommonException("该用户不存在");
        }

        if (Objects.isNull(user)) {
            throw new CommonException("该用户不存在");
        }

        UserBO userBO = new UserBO();
        BeanUtil.copyProperties(user, userBO);

        /**
         * TODO 查询用户的权限信息，授权
         */
        List<Role> roleList = roleMapper.selectRolesByUserId(user.getUserId());

        List<RoleBO> roleBOList = roleList.stream().map(role -> {
            RoleBO roleBO = new RoleBO();
            BeanUtils.copyProperties(role, roleBO);
            List<Menu> menuList= menuMapper.selectMenuByRoleId(role.getRoleId());
            List<MenuBO> menuBOList = menuList.stream().map(menu -> {
                MenuBO menuBO = new MenuBO();
                BeanUtils.copyProperties(menu, menuBO);
                log.info("menuBO => {}", menuBO.getMenuCode());
                return menuBO;
            }).collect(Collectors.toList());
            roleBO.setMenuBOList(menuBOList);
            return roleBO;
        }).collect(Collectors.toList());

        ResultModel<LoginUserDetailBO> resultModel = new ResultModel<>();
        resultModel.setMsg("根据用户名查询用户的角色和权限成功");
        resultModel.setRes(new LoginUserDetailBO(userBO, roleBOList));
        return resultModel;
    }
}
